import { fromHTML, waitFor } from '../../../common';

export type MenuElement = Brand<HTMLElement, 'menu'>;
export type MenuItemElement = Brand<HTMLElement, 'menu-item'>;

type MenuCallback = (menuEl: MenuElement, id: string) => any;

const artistMenuCallbacks: MenuCallback[] = [];
const playlistMenuCallbacks: MenuCallback[] = [];
const albumMenuCallbacks: MenuCallback[] = [];
const trackMenuCallbacks: MenuCallback[] = [];

addEventListener('mousedown', async (e) => {
	const path = e.composedPath()
		.slice(0, -5)
		.filter(el => el instanceof HTMLElement) as HTMLElement[];

	const buttonEl = path.find(el => el.matches('amp-contextual-menu-button'));
	if (!buttonEl) return;

	const shadowMenuEl = await waitFor('amp-contextual-menu', undefined, 300);
	if (!shadowMenuEl?.shadowRoot) return;

	const menuEl = await waitFor<MenuElement>('ul', undefined, 300, shadowMenuEl.shadowRoot);
	if (!menuEl) return;

	const collectionId = location.href.split('/').pop();

	const artistHeaderEl = path.find(el => el.classList.contains('artist-header'));
	if (collectionId && artistHeaderEl) {
		for (const cb of artistMenuCallbacks) cb(menuEl, collectionId);
		return;
	}

	const collectionHeaderEl = path.find(el => el.classList.contains('container-detail-header'));
	if (collectionId && collectionHeaderEl) {
		if (location.href.includes('/playlist/')) {
			for (const cb of playlistMenuCallbacks) cb(menuEl, collectionId);
			return;
		}

		if (location.href.includes('/album/')) {
			for (const cb of albumMenuCallbacks) cb(menuEl, collectionId);
			return;
		}
	}

	const trackEl = path.find(el => el.classList.contains('songs-list-row'));
	const trackId = trackEl?.previousElementSibling?.getAttribute('href')?.split('/').pop();
	if (trackId) {
		for (const cb of trackMenuCallbacks) cb(menuEl, trackId);
		return;
	}
});

export function createMenuItem(text: string, icon: string, multiline: boolean = false): MenuItemElement {
	return fromHTML(`
		<amp-contextual-menu-item hydrated>
			<li class="contextual-menu__item">
				<button title="Share" style="${multiline ? "height: auto; padding-top: 8px; padding-bottom: 8px;" : ""}">
					<span class="contextual-menu__item-option-wrapper">
						<span class="contextual-menu-item__option-text">${text}</span>
						<span class="contextual-menu-item__option-text contextual-menu-item__option-text--after"></span>
						<span class="contextual-menu-item__icon-container">
							${icon}
						</span>
					</span>
				</button>
			</li>
		</amp-contextual-menu-item>
	`) as MenuItemElement;
}

export function showMenuItem(menuEl: MenuElement, itemEl: MenuItemElement, priority: number = Number.MAX_VALUE) {
	itemEl.addEventListener('click', () => {
		const scrimButtonEl = menuEl.previousElementSibling?.shadowRoot?.lastElementChild as HTMLButtonElement | null;
		scrimButtonEl?.click();
	}, { once: true });

	const buttonEls = Array.from(itemEl.querySelectorAll('amp-contextual-menu-item')) as HTMLElement[];
	itemEl.setAttribute('data-priority', priority.toString());

	if (buttonEls.length === 0) {
		menuEl.prepend(itemEl);
		return;
	}

	let bestDist = Number.MAX_VALUE;
	let refEl = buttonEls[0];

	for (const buttonEl of buttonEls) {
		const dist = Math.abs(Number(buttonEl.getAttribute('data-priority')) - priority);
		if (dist >= bestDist) continue;

		bestDist = dist;
		refEl = buttonEl;
	}

	if (priority > Number(refEl.getAttribute('data-priority'))) {
		refEl.after(itemEl);
	} else {
		refEl.before(itemEl);
	}
}

export function onArtistMenu(cb: MenuCallback) {
	artistMenuCallbacks.push(cb);
}

export function onPlaylistMenu(cb: MenuCallback) {
	playlistMenuCallbacks.push(cb);
}

export function onAlbumMenu(cb: MenuCallback) {
	albumMenuCallbacks.push(cb);
}

export function onTrackMenu(cb: MenuCallback) {
	trackMenuCallbacks.push(cb);
}
